package logic;

import java.awt.geom.Rectangle2D;
import java.util.Comparator;

import common.point.PointG;

import util.Util;
import vis.GPoint;

public class Line implements Cloneable {
	 protected GPoint[] p = new GPoint[2];
	 protected Polygon parent = null;
	 public int meta1 = 0;
	 public int meta2 = 0;
	 public int meta3 = 0;
	 
	 public Polygon getParent() {
		return parent;
	}

	public void setParent(Polygon parent) {
		this.parent = parent;
	}

	public Line(GPoint p1, GPoint p2)
	 {
		 p[0] = p1;
		 p[1] = p2;
		 p[0].setParent(this);
		 p[1].setParent(this);
	 }
	 
	 public Line(double x1, double y1, double x2, double y2)
	 {
		 p[0] = new GPoint(x1, y1);
		 p[0].setParent(this);
		 p[1] = new GPoint(x2, y2);
		 p[1].setParent(this);
	 }
	 
	 public void makeRight()
	 {
		 if(p[0].X > p[1].X)
		 {
			 GPoint tmp = p[1];
			 p[1] = p[0];
			 p[0] = tmp;
		 }
	 }
	 
	 public GPoint getP1() { return p[0]; }
	 public GPoint getP2() { return p[1]; }
	 public double getLength() { return Util.getDist(p[0].X, p[0].Y, p[1].X, p[1].Y); }
	 
	 public String toString()
	 {
		 return "[Line : (" + p[0].X + ", " + p[0].Y + ")-(" + p[1].X + ", " + p[1].Y + ")]"; 
	 }
	 
	 public static GPoint intersect(Line a, Line b)
	 {
		 if(!a.getBoundingRect().intersects(b.getBoundingRect())) return null;
		 
		 if((a.p[0].X == a.p[1].X) && (b.p[0].X == b.p[1].X))
		 {
			 if(a.p[0].X == b.p[0].X)
				 return a.p[0];
			 else
				 return null;
		 }
		 
		 if(a.p[0].X == a.p[1].X)
		 {
			 return null;
		 }
		 
		 if(b.p[0].X == b.p[1].X)
		 {
			 return null;
		 }
		 
		 double a1 = (a.p[1].Y - a.p[0].Y) / (a.p[1].X - a.p[0].X);
		 double a2 = (b.p[1].Y - b.p[0].Y) / (b.p[1].X - b.p[0].X);
		 if(a1 == a2) return null;
		 
		 double x1 = a.p[0].X;
		 double y1 = a.p[0].Y;
		 double x2 = a.p[1].X;
		 double y2 = a.p[1].Y;
		 double x3 = b.p[0].X;
		 double y3 = b.p[0].Y;
		 double x4 = b.p[1].X;
		 double y4 = b.p[1].Y;
		 
		 double PX = ((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
		 double PY = ((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
		 
		 if(a.getBoundingRect().contains(PX, PY) && b.getBoundingRect().contains(PX, PY))
			 return new GPoint(PX, PY); 
		 else
			 return null;
	 }
	 
	 public GPoint findIntersection(Line o)
	 {
		 return intersect(this, o);
	 }
	 
	 private Rectangle2D getBoundingRect()
	 {
		 double minX = (p[0].X < p[1].X) ? p[0].X : p[1].X;
		 double minY = (p[0].Y < p[1].Y) ? p[0].Y : p[1].Y;
		 double maxX = (p[0].X > p[1].X) ? p[0].X : p[1].X;
		 double maxY = (p[0].Y > p[1].Y) ? p[0].Y : p[1].Y;
		 return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
	 }
	 
	 public static final Comparator<Line> FirstX = new Comparator<Line>() {
		@Override
		public int compare(Line arg0, Line arg1) {
			return Double.compare(arg0.getP1().getX(), arg1.getP1().getX());
		}
	 };
	 
	 public boolean equals(Line l)
	 {
		 return(l.p[0].equals(p[0]) && l.p[1].equals(p[1])) || (l.p[0].equals(p[1]) && l.p[1].equals(p[0]));
	 }
	 
	 public boolean isBelowAt(Line l2, double x)
	 {
		 double y1 = Util.lerpY(p[0], p[1], x);
		 double y2 = Util.lerpY(l2.p[0], l2.p[1], x);
		 return y1 < y2;
	 }
	 
	 public boolean isAboveAt(Line l2, double x)
	 {
		 double y1 = Util.lerpY(p[0], p[1], x);
		 double y2 = Util.lerpY(l2.p[0], l2.p[1], x);
		 return y1 > y2;
	 }
}
